#include "ip2region.h"

#include <lua.h>
#include <lauxlib.h>

struct ut_ip2region
{
	ip2region_t ip2r;
};

static int
lnew(lua_State *L) {
	const char *dbpath = luaL_checkstring(L, 1);
	struct ut_ip2region *q = (struct ut_ip2region*)lua_newuserdata(L, sizeof(*q));

	ip2region_t ip2r = skynet_malloc(sizeof(ip2region_entry));
	if (ip2r == NULL)
		luaL_error(L, "failed to malloc ip2r");
	memset(ip2r, 0x00, sizeof(ip2region_entry));
	ip2r->headerLen = 0;
	ip2r->HeaderSip = (uint_t *)skynet_malloc(TOTAL_HEADER_LENGTH);
	if (ip2r->HeaderSip == NULL)
		luaL_error(L, "failed to malloc header sip");

	ip2r->HeaderPtr = (uint_t *)skynet_malloc(TOTAL_HEADER_LENGTH);
	if (ip2r->HeaderPtr == NULL) {
		skynet_free(ip2r->HeaderSip);
		luaL_error(L, "failed to malloc header ptr");
	}

	ip2r->dbHandler = fopen(dbpath, "rb");
	if (ip2r->dbHandler == NULL) {
		skynet_free(ip2r->HeaderSip);
		skynet_free(ip2r->HeaderPtr);
		luaL_error(L, "failed to load the db file");
	}

	ip2r->firstIndexPtr	= 0;
	ip2r->lastIndexPtr	= 0;
	ip2r->totalBlocks	= 0;
	ip2r->dbBinStr		= NULL;
	q->ip2r = ip2r;

	luaL_getmetatable(L, "mk.ip2region");
	lua_setmetatable(L, -2);
	return 1;
}

static int
lrelease(lua_State *L) {
	struct ut_ip2region* ut = (struct ut_ip2region *)luaL_checkudata(L, 1, "mk.ip2region");
	skynet_free(ut->ip2r->HeaderSip);
	ut->ip2r->HeaderSip = NULL;
	skynet_free(ut->ip2r->HeaderPtr);
	ut->ip2r->HeaderPtr = NULL;

	//close the db file resource
	if ( ut->ip2r->dbHandler != NULL ) {
		fclose(ut->ip2r->dbHandler);
		ut->ip2r->dbHandler = NULL;
	}

	//free the db binary string
	if ( ut->ip2r->dbBinStr != NULL ) {
		skynet_free(ut->ip2r->dbBinStr);
		ut->ip2r->dbBinStr = NULL;
	}

	return 0;
}

static int
lsearch(lua_State *L) {
	struct ut_ip2region* ut = (struct ut_ip2region *)luaL_checkudata(L, 1, "mk.ip2region");
	const char *strip = luaL_checkstring(L, 2);
	datablock_entry datablock;
	memset(&datablock, 0x00, sizeof(datablock_entry));
	ip2region_btree_search_string(ut->ip2r, strip, &datablock);
	lua_pushstring(L, datablock.region);
	return 1;
}

static const luaL_Reg m[] = {
	{ "search", lsearch },
	{ NULL, NULL },
};

static const luaL_Reg l[] = {
	{"new", lnew },
	{ NULL, NULL },
};

int
luaopen_ip2region(lua_State *L) {
	// 生成一个元表 存在注册表 key mk.ip2region val = 元表
	if (luaL_newmetatable(L, "mk.ip2region")) {
		luaL_newlib(L, m);
		lua_setfield(L, -2, "__index");
		lua_pushcfunction(L, lrelease);
		lua_setfield(L, -2, "__gc");
	}
	luaL_newlib(L, l);
	return 1;
}